home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / a_utils / expanded.lha / expanded / src / SubSet.C < prev    next >
C/C++ Source or Header  |  1992-03-19  |  46KB  |  1,592 lines

  1. //
  2. // Linear-Affine-Projective Geometry Package
  3. //
  4. // SubSet.C
  5. //
  6. // $Header$
  7. //
  8. // William J.R. Longabaugh 
  9. // University of Washington
  10. //
  11. // Implementation of the linear-affine-projective geometry
  12. // package described in William J.R. Longabaugh, "An Expanded
  13. // System for Coordinate-Free Geometric Programming", Master's 
  14. // thesis, University of Washington, 1992.
  15. //
  16. // Copyright (c) 1992, William J.R. Longabaugh
  17. //   Copying, use and development for non-commercial purposes permitted.
  18. //   All rights for commercial use reserved.
  19. //   This software is unsupported and without warranty; it is
  20. //   provided "as is".
  21. //
  22. // ***********************************************************************
  23.  
  24. #include <math.h>
  25. #include "Lap.h"
  26.  
  27. // ***********************************************************************
  28. //
  29. // Class for exclusive use of SubSet class to hold onto data for a 
  30. // subset.  What is really wanted is a simple structure; I am not
  31. // really interested in data hiding here.  However, under g++ 1.37.1,
  32. // this apparently MUST be a class, not a struct, so that virtual 
  33. // ptrs of class members are initialized.  Also, the fact that class
  34. // members will be automatically initialized using null constructors
  35. // is desirable.  Thus, this is a class, but note that all members
  36. // are public, allowing unlimited access.
  37. // Note that since there is a VSubSet in this block, SubSets
  38. // must in fact be implemented as pointers to information blocks:
  39. //
  40.  
  41. class SubSetInfo {
  42.  
  43.   public:
  44.  
  45.     SubSetType t;                // Type of subset
  46.     char     name[MAX_NAMESIZE];        // Name of subset
  47.     Space    s;                         // Space containing subset
  48.     int      d;                // Dimension of subset
  49.     Matrix   tstmtx;            // Testing matrix
  50.     Matrix   fullbas;            // Matrix rep. of full basis
  51.     int      isOffset;            // Column for testing
  52.     int      substart;            // Column for testing
  53.     int      zerostart;            // Column for testing
  54.     Scalar   offset;            // Offset of affine hyperplane
  55.     Matrix   fromfull;            // Matrix from full to subset basis
  56.     Matrix   tofull;            // Matrix from subset to full basis
  57.     GeObType accepts;            // Type of object in subset
  58.     VSubSet  tansub;            // Tangent subset
  59.  
  60. // Constructors/Destructors:
  61.  
  62.         SubSetInfo(void)  {}         // Null constructor
  63.         ~SubSetInfo(void) {}         // Destructor
  64.         SubSetInfo(char* namein, int d); // Used to build error info block
  65. };
  66.  
  67. // ***********************************************************************
  68. //
  69. // Declare the existence of the error info block:
  70.  
  71. static SubSetInfo errinfo;
  72.  
  73.  
  74. // ***********************************************************************
  75. // ***********************************************************************
  76. //
  77. // SubSetInfo Class
  78. //
  79. // ***********************************************************************
  80. // ***********************************************************************
  81. //
  82. // Special constructor used to build an "error info block".  Uninitialized
  83. // subsets point to that block.
  84.  
  85. SubSetInfo::SubSetInfo(char* namein, int dim)
  86. {
  87.   t = NULL_SUBSET;
  88.   d = dim;
  89.   isOffset = -1;
  90.   substart = -1;
  91.   zerostart = -1;
  92.   offset = 0.0;
  93.   accepts = NULL_GEOB;
  94.  
  95. // Local copy of the debug name:
  96.  
  97.   strncpy(name, namein, MAX_NAMESIZE - 1);
  98.   name[MAX_NAMESIZE - 1] = '\0';
  99. }
  100.  
  101. // ***********************************************************************
  102. // ***********************************************************************
  103. //
  104. // SubSet Class
  105. //
  106. // ***********************************************************************
  107. // ***********************************************************************
  108. //
  109. // Private/protected member functions
  110. //
  111. // ***********************************************************************
  112. //
  113. // Great candidates for inlining, but see the comment in the file
  114. // Space.C:
  115. //
  116. // ***********************************************************************
  117.  
  118. int SubSet::IsOffset(void) {return info->isOffset;}
  119.  
  120. // ***********************************************************************
  121.  
  122. Scalar SubSet::Offset(void) {return info->offset;}
  123.  
  124. // ***********************************************************************
  125.  
  126. Matrix& SubSet::FromFull(void) {return info->fromfull;}
  127.  
  128. // ***********************************************************************
  129.  
  130. Matrix& SubSet::ToFull(void) {return info->tofull;}
  131.  
  132. // ***********************************************************************
  133.  
  134. Matrix& SubSet::AugBasis(void) {return info->fullbas;}
  135.  
  136. // ***********************************************************************
  137. //
  138. // Used to normalize the representation of projective points contained
  139. // in an affine subset.  It does not do ANY error checks, so beware!
  140. //
  141.  
  142. GeOb SubSet::Normalize(GeOb& ob)
  143. {
  144.   Matrix newmat = ob.MatrixRep();
  145.   Scalar factor = info->offset / (newmat * info->tstmtx)[0][info->isOffset];
  146.  
  147.   GeOb retval(ob.Holds(), ob.SpaceOf(), factor * newmat);
  148.   return retval;
  149. }
  150.  
  151. // ***********************************************************************
  152. //
  153. // Given two affine subsets in projective spaces, determine the
  154. // scalar factor that must be applied to place the origin point
  155. // of the first at the offset of the secong origin point
  156. // It does not do ANY error checks, so beware!
  157. //
  158.  
  159. Scalar SubSet::NormVal(SubSet& targ)
  160. {
  161.   Matrix newmat = targ.ToFull()[targ.info->isOffset];
  162.   Scalar factor = info->offset / (newmat * info->tstmtx)[0][info->isOffset];
  163.   return factor;
  164. }
  165.  
  166. // ***********************************************************************
  167. // 
  168. // This function copies only a maximum number of characters into
  169. // the debug name buffer.
  170. //
  171.  
  172. void SubSet::CopyDebugName(char* buf)
  173. {
  174.   strncpy(info->name, buf, MAX_NAMESIZE - 1);
  175.   info->name[MAX_NAMESIZE - 1] = '\0';
  176.   return;
  177. }
  178.  
  179. // ***********************************************************************
  180. // 
  181. // This function builds a tagged debug name.  The user is responsible
  182. // for calling DestroyTagName() when finished.
  183. //
  184.  
  185. char* SubSet::BuildTagName(char* tag, Space& s) 
  186. {
  187.   int len = strlen(tag);
  188.   char* buf = new char[MAX_NAMESIZE + len];
  189.  
  190.   strncpy(buf, tag, len);
  191.   s.Name(buf + len);
  192.   return (buf);
  193. }
  194.  
  195. // ***********************************************************************
  196. // 
  197. // This function builds a tagged debug name.  The user is responsible
  198. // for calling DestroyTagName() when finished.
  199. //
  200.  
  201. char* SubSet::BuildTagName(char* tag, SubSet& s) 
  202. {
  203.   int len = strlen(tag);
  204.   char* buf = new char[MAX_NAMESIZE + len];
  205.  
  206.   strncpy(buf, tag, len);
  207.   s.Name(buf + len);
  208.   return (buf);
  209. }
  210.  
  211. // ***********************************************************************
  212. // 
  213. // This function kills a tagged debug name.
  214. //
  215.  
  216. void SubSet::DestroyTagName(char* buf) 
  217. {
  218.   delete buf;
  219. }
  220.  
  221. // ***********************************************************************
  222. //
  223. // This little routine is used by subset constructors to convert lists
  224. // of arbitrary geometric objects into objects of the desired type
  225. // in the desired space.  A matrix containing std. coords of the
  226. // objects is built:
  227. //
  228.  
  229. Boolean SubSet::ConvertList(GeObList& v, GeObType targ,
  230.                 Space& destspace, Matrix* temp)
  231. {
  232.   for (int i = 0; i < v.Length(); i++) {
  233.     GeOb hold = v[i].MapTo(targ);
  234.     if (hold.SpaceOf() != destspace) {
  235.       return (FALSE);
  236.     } 
  237.     (*temp)[i] = hold.MatrixRep()[0];
  238.   }
  239.   return (TRUE);
  240. }
  241.  
  242. // ***********************************************************************
  243. //
  244. // Modified Gram-Schmidt orthogonalization.  The "have" matrix has
  245. // orthonormal rows, and represents the existing orthonormal basis
  246. // of some subspace.  The "try" matrix contains vectors to use
  247. // for constructing a total of "dim" orthonormal vectors; any
  248. // vectors in the try matrix that are not linearly independent
  249. // are skipped.  We set the error flag if there are not enough vectors
  250. // to use for meeting the "dim" target:
  251. //
  252.  
  253. Matrix SubSet::GSO(Matrix& have, Matrix& try, int start,
  254.            int dim, Boolean* error)
  255. {
  256.   Matrix retval(dim, have.Columns());
  257.   int count = 0;
  258.  
  259. // Start by filling in with the vectors we already have:
  260.  
  261.   for (int i = 0; i < have.Rows(); i++) {
  262.     retval[i] = have[i];
  263.     count++;
  264.   }
  265.  
  266. // Go through the test vectors until we have enough:
  267.  
  268.   int tryrow = start;
  269.   while (count < dim) {
  270.     Matrix nextrow(1, have.Columns());
  271.     if (tryrow == try.Rows()) {
  272.       *error = TRUE;
  273.       return retval;
  274.     }
  275.     if (this->Orth(&retval, count, try, tryrow)) {
  276.       count++;
  277.     }
  278.     tryrow++;
  279.   }
  280.   *error = FALSE;
  281.   return retval;
  282. }
  283.  
  284. // ***********************************************************************
  285. //
  286. // Support for GSO.  Does the actual GSO for a vector.  Returns TRUE
  287. // iff the vector could be orthogonalized.  FALSE means it was
  288. // contained in the subspace we have built.  
  289. //
  290.  
  291. Boolean SubSet::Orth(Matrix* have, int count, Matrix& try, int tryrow)
  292. {
  293.   Scalar factor;
  294.   Scalar mag;
  295.  
  296. // Modified GSO does orthogonalization incrementally, once for each
  297. // vector we already have.  If we ever end up with the zero vector,
  298. // the attempt has failed and we need to return.  Otherwise, normalize
  299. // as we go:
  300.  
  301.   Matrix hold = try[tryrow];
  302.   for (int i = 0; i < count; i++) {
  303.     Matrix proj = (*have)[i];
  304.     factor = (proj * Transpose(hold))[0][0] / (proj * Transpose(proj))[0][0];
  305.     hold -= (factor * proj);
  306.     mag = sqrt((hold * Transpose(hold))[0][0]);    
  307.     if (fabs(mag) < EPSILON) {
  308.       return (FALSE);
  309.     } else {
  310.       hold = hold / mag;
  311.     }
  312.   }
  313.   (*have)[count] = hold[0];  
  314.   return (TRUE);
  315. }
  316.  
  317. // ***********************************************************************
  318. //
  319. // Build a subset from an info block:
  320. //
  321.  
  322. SubSet::SubSet(SubSetInfo* ts)
  323. {
  324.   info = ts;
  325.   type = ANY_SUBSET;
  326.   holds = ts->t;
  327. }
  328.  
  329. // ***********************************************************************
  330. //
  331. // Dumps data for a subset:
  332. //
  333.  
  334. void SubSet::data_out(ostream &c, int indent, char* name) 
  335. {
  336.   char *ibloc = new char[indent + 1];
  337.   for (int i = 0; i < indent; i++) {
  338.     *(ibloc + i) = ' ';
  339.   }
  340.   *(ibloc + indent) = '\0';
  341.  
  342.   c << ibloc << ast;
  343.   c << ibloc << name;
  344.   c << ibloc << "Type of subset: ";
  345.   SubSetTypeOut(c, type);
  346.   c << "\n";
  347.   c << ibloc << "Currently holds: ";
  348.   SubSetTypeOut(c, holds);
  349.   c << "\n";
  350.   if (holds != NULL_SUBSET) {
  351.     c << ibloc << "Name of subset: " << info->name << "\n";
  352.     c << ibloc << "Embedding space:\n";
  353.     info->s.debug_out(c, indent + ERR_IND);
  354.     c << ibloc << "Dimension: " << info->d << "\n";
  355.     c << ibloc << "Type of object in subset: ";
  356.     GeObTypeOut(c, info->accepts);
  357.     c << "\n";
  358.     c << ibloc << "Offset value column: " << info->isOffset << "\n";
  359.     c << ibloc << "Subset value starting column: " << info->substart << "\n";
  360.     c << ibloc << "Zero value starting column: " << info->zerostart << "\n";
  361.     c << ibloc << "Offset of affine hyperplane: " << info->offset << "\n";
  362.     c << ibloc << "Memory location: " << (long)info << "\n";
  363.     c << ibloc << "Matrix representation of testing matrix:\n";
  364.     info->tstmtx.debug_out(c, indent + ERR_IND);
  365.     c << ibloc << "Matrix representation of full basis matrix:\n";
  366.     info->fullbas.debug_out(c, indent + ERR_IND);
  367.     c << ibloc << "Matrix to convert to subset basis from full basis:\n";
  368.     info->fromfull.debug_out(c, indent + ERR_IND);
  369.     c << ibloc << "Matrix to convert to full basis from subset basis:\n";
  370.     info->tofull.debug_out(c, indent + ERR_IND);
  371.     c << ibloc << "Tangent subset:\n";
  372.     info->tansub.debug_out(c, indent + ERR_IND);
  373.   }  
  374.   c << ibloc << ast;
  375.  
  376.   delete ibloc;
  377.   return;
  378. }
  379.  
  380. // ***********************************************************************
  381. //
  382. // Public member functions
  383. //
  384. // ***********************************************************************
  385.  
  386. SubSet::SubSet(void) {type = ANY_SUBSET; holds = NULL_SUBSET; info = &errinfo;}
  387.  
  388. // ***********************************************************************
  389. //
  390. // Memberwise initialization:
  391. //
  392.  
  393. SubSet::SubSet(SubSet &s)
  394. {
  395.   info = s.info;
  396.   type = ANY_SUBSET;
  397.   holds = s.holds;
  398. }  
  399.  
  400. // ***********************************************************************
  401. //
  402. // Memberwise assignment:
  403. //
  404.  
  405. SubSet& SubSet::operator=(SubSet &s)
  406. {
  407. //
  408. // This weird checking is required to bypass the apparent inheritance of
  409. // assignment under g++ 1.37:
  410. //
  411.   if ((type != ANY_SUBSET) &&
  412.       ((type != s.holds) && (s.holds != NULL_SUBSET))) {
  413.     errh.ErrorExit("SubSet& SubSet::operator=(SubSet &)",
  414.                    "Illegal assignment attempted", *this, s);
  415.   }
  416.   holds = s.holds;
  417.   info = s.info;
  418.   return (*this);
  419. }  
  420.  
  421. // ***********************************************************************
  422. //
  423. // Output for debugging:
  424. //
  425.  
  426. void SubSet::debug_out(ostream &c, int indent) 
  427. {
  428.   static char* name = "SubSet object\n";
  429.   this->data_out(c, indent, name);
  430.   return;
  431. }
  432.  
  433. // ***********************************************************************
  434. //
  435. // Great candidates for inlining, but see the comment in the file
  436. // Space.C:
  437. //
  438. // ***********************************************************************
  439.  
  440. char* SubSet::Name(char *buf) {return (strcpy(buf, info->name));}
  441.  
  442. // ***********************************************************************
  443.  
  444. Space SubSet::EmbeddingSpace(void) {return (info->s);}
  445.  
  446. // ***********************************************************************
  447.  
  448. GeObType SubSet::Accepts(void) {return (info->accepts);}
  449.  
  450. // ***********************************************************************
  451.  
  452. int SubSet::Dim(void) {return (info->d);}
  453.  
  454. // ***********************************************************************
  455. //
  456. // Returns TRUE iff the subset spans the entire embedding space.
  457. //
  458.  
  459. Boolean SubSet::IsFullSpace(void)
  460. {
  461.   if ((info->t == PROJECTIVE_SUBSET) && (info->s.Holds() == VEC_SPACE)) {
  462.     return (info->d + 1 == (info->s).Dim());
  463.   } else if ((info->t == AFFINE_SUBSET) && (info->s.Holds() == PROJ_SPACE)) {
  464.     return (FALSE);
  465.   } else {
  466.     return (info->d == (info->s).Dim());
  467.   }
  468. }
  469.  
  470. // ***********************************************************************
  471. //
  472. // Returns true iff the subset is projective and was constructed
  473. // by specifying a set of base points.
  474.  
  475. Boolean SubSet::HasRemovedPoints(void)
  476. {
  477.   return ((holds == PROJECTIVE_SUBSET) && (info->substart != 0));
  478. }
  479.  
  480. // ***********************************************************************
  481. //
  482. // Returns a list of points that spans the points at infinity.  Only
  483. // applicable for affine subsets defined on projective spaces.
  484.  
  485. GeObList SubSet::AtInfinity(void)
  486. {
  487.   static char* sig = "GeObList SubSet::AtInfinity(void)";
  488.  
  489.   if ((holds != AFFINE_SUBSET) || (info->s.Holds() != PROJ_SPACE)) {
  490.     errh.ErrorExit(sig, "Must be affine subset in projective space", *this);
  491.   }   
  492.  
  493. // The tofull matrix encodes the points at infinity.  Extract the
  494. // std. coords. and build the list.
  495.  
  496.   int rows = info->tofull.Rows() - 1;
  497.   GeObList retval(rows);
  498.  
  499.   for (int i = 0; i < rows; i++) {
  500.     retval[i] = GeOb(info->accepts, info->s, info->tofull[i]);
  501.   }
  502.   return (retval);
  503. }
  504.  
  505. // ***********************************************************************
  506. //
  507. // Returns the tangent subset associated with an affine subset.
  508. // If embedding space is affine, the subset is a vector subspace of
  509. // the tangent space.  If embedding space is a vector space, the subset
  510. // is a vector subset of that space.  If it is in a projective
  511. // space, it is an error to use this.  
  512. // 
  513.  
  514. VSubSet SubSet::TangentSub(void)
  515. {
  516.   static char* sig = "VSubSet SubSet::TangentSub(void)";
  517.  
  518.   if (holds != AFFINE_SUBSET) {
  519.     errh.ErrorExit(sig, "Only allowed for affine subsets", *this);
  520.   }
  521.   if ((info->s).Holds() == PROJ_SPACE) {
  522.     errh.ErrorExit(sig, "Embedding space cannot be projective", *this);
  523.   }
  524.  
  525. // Perhaps the user has already requested the tangent space, so one has
  526. // been built.  Reuse this tangent space.
  527.  
  528.   if ((info->tansub).Holds() != NULL_SUBSET) {
  529.     return (info->tansub);
  530.   }
  531.  
  532. // If the embedding space is an affine space, and the subset is the
  533. // same dimension, the tangent subset is simply the full standard
  534. // subset of the tangent space:
  535.  
  536.   if (((info->s).Holds() == AFF_SPACE) && (this->IsFullSpace())) {
  537.     info->tansub = (info->s).GetSpace(TANGENT).FullSet();
  538.     return (info->tansub);
  539.   }
  540.  
  541. // Need to build a new tangent space.
  542.  
  543.   SubSetInfo* temp = new SubSetInfo;
  544.   Boolean isvs = (info->s).Holds() == VEC_SPACE;
  545.  
  546.   char* tag = this->BuildTagName("Subset tangent to ", *this);
  547.   strncpy(temp->name, tag, MAX_NAMESIZE - 1);
  548.   temp->name[MAX_NAMESIZE - 1] = '\0';
  549.   this->DestroyTagName(tag);
  550.  
  551.   temp->t = LINEAR_SUBSET;
  552.   temp->s = (isvs) ? info->s : (info->s).GetSpace(TANGENT);
  553.   temp->d = info->d;
  554.   temp->offset = 0.0;
  555.   temp->accepts = (isvs) ? info->accepts : AFF_VECTOR;
  556.   temp->substart = 0;
  557.  
  558. // If the parent space is a vector space, the situation is simple.
  559. // The tofull matrix omits the offset row, and we expect the
  560. // component in the offset direction to be zero.  Fromfull has
  561. // one less column:
  562.  
  563.   if (isvs) {
  564.     temp->tofull = Matrix(info->d, info->s.Dim());
  565.     for (int i = 0; i < info->d; i++) {
  566.       temp->tofull[i] = info->tofull[i];
  567.     }
  568.     temp->fullbas = info->fullbas;
  569.     temp->tstmtx = info->tstmtx;
  570.     temp->zerostart = info->isOffset;
  571.     temp->isOffset = -1;
  572.     Matrix trg = ZeroMatrix(temp->s.Dim(), temp->d);
  573.       for (int j = 0; j < temp->d; j++) {
  574.         trg[j][j] = 1.0;
  575.       }
  576.     temp->fromfull = temp->tstmtx * trg;
  577.   } else { 
  578.  
  579. // If the parent space is an affine space, the situation is more involved,
  580. // since we need to build the subset in the separate tangent vector
  581. // space.  Fortunately, the basis for the subset is expressed using
  582. // tangent space vectors and an offset, so all we have to do is
  583. // omit the offset and convert the representation:
  584.  
  585.     temp->tofull = Matrix(info->d, info->s.Dim());
  586.     Matrix convert = info->tofull * Transpose(info->s.HoistTangent());
  587.     int slot = 0;
  588.     for (int i = 0; i < convert.Rows(); i++) {
  589.       if (i != info->isOffset) {
  590.         temp->tofull[slot++] = convert[i];
  591.       }
  592.     }
  593.     Boolean errflag;
  594.     temp->fullbas = this->GSO(temp->tofull, IdentityMatrix(temp->s.Dim()),
  595.                   0, temp->s.Dim(), &errflag);
  596.     if (errflag) {
  597.       errh.ErrorExit(sig, "Unexpected error", *this);
  598.     }
  599.     temp->tstmtx = Inverse(temp->fullbas);
  600.     Matrix trg = ZeroMatrix(temp->s.Dim(), temp->d);
  601.     for (int k = 0; k < temp->d; k++) {
  602.       trg[k][k] = 1.0;
  603.     }
  604.     temp->fromfull = temp->tstmtx * trg; 
  605.     temp->zerostart = info->isOffset;
  606.     temp->isOffset = -1;
  607.   }
  608.  
  609. // Construct the new subset and return it;
  610.  
  611.   info->tansub = SubSet(temp);    
  612.   return (info->tansub);
  613. }
  614.  
  615. // ***********************************************************************
  616. //
  617. // Returns true if the given geometric object is in the subset.
  618. // (Actually, it is true if the object is within EPSILON).
  619.  
  620. Boolean SubSet::IsIn(GeOb &g)
  621. {
  622.   Scalar testval = EPSILON;
  623.  
  624. // First check if object is in the embedding space.  If not, return
  625. // false:
  626.  
  627.   GeOb temp = g.MapTo(info->accepts);
  628.   if (temp.SpaceOf() != info->s) {
  629.     return (FALSE);
  630.   }
  631.  
  632. // Then multiply the object matrix by the testing matrix, and
  633. // compare the coordinate results with the targets.
  634.  
  635.   Matrix result = temp.MatrixRep() * info->tstmtx;
  636.  
  637. // Affine subsets need a coord. == offset.  If this is an affine
  638. // subset of a projective space, we just need to make sure the
  639. // offset is not zero (but also scale the epsilon to take into account
  640. // the scaling of the offset to the desired value).  If this is a
  641. // projective subset, we need to make sure the GeOb is not a base point:
  642.  
  643.   if (info->t == AFFINE_SUBSET) {
  644.     if (info->s.Holds() == PROJ_SPACE) {
  645.       if (fabs(result[0][info->isOffset]) <= EPSILON) {
  646.         return (FALSE);
  647.       } else {
  648.         Scalar factor = fabs(info->offset / result[0][info->isOffset]);
  649.         testval = testval / factor;
  650.       }
  651.     } else {
  652.       if (fabs(result[0][info->isOffset] - info->offset) > EPSILON) {
  653.         return (FALSE);
  654.       }
  655.     }
  656.   } else if (info->t == PROJECTIVE_SUBSET) {
  657.     Boolean allzero = TRUE;
  658.     for (int i = info->substart; i < info->zerostart; i++) {
  659.       if (fabs(result[0][i]) > EPSILON) {
  660.         allzero = FALSE;
  661.     break;
  662.       }
  663.     }
  664.     if (allzero) {
  665.       return (FALSE);
  666.     }
  667.   }
  668.  
  669. // Coords. for space orthogonal to subset == 0:
  670.  
  671.   for (int i = info->zerostart; i < result.Columns(); i++) {
  672.     if (fabs(result[0][i]) > testval) {
  673.       return (FALSE);
  674.     }
  675.   }
  676.  
  677.   return (TRUE);
  678. }
  679.  
  680. // ***********************************************************************
  681. //
  682. // Given another subset, this function returns TRUE iff the given subset
  683. // is a subset of this subset.  Currently not implemented for
  684. // projective subsets with removed base points.  Note that only
  685. // comparisons of subsets of identical type are allowed.  (The system
  686. // does not test if an affine subset is a subset of a vector subset,
  687. // but simply answers FALSE).
  688.  
  689. Boolean SubSet::IsSubset(SubSet &s)
  690. {
  691.   static char* sig = "Boolean SubSet::IsSubset(SubSet&)";
  692.   int toprow;
  693.  
  694. // A quick kill is if the subsets are the same definition:
  695.  
  696.   if (info == s.info) {
  697.     return (TRUE);
  698.   }
  699.  
  700. // Check that the operation is valid:
  701.  
  702.   if (this->HasRemovedPoints() || s.HasRemovedPoints()) {
  703.     errh.ErrorExit(sig,
  704.       "Comparing projective subsets with removed points not implemented",
  705.       *this, s);
  706.   }   
  707.  
  708. // Make sure the embedding spaces and subset types match:
  709.  
  710.   if (s.info->s != info->s) {
  711.     return (FALSE);
  712.   }
  713.   if (s.holds != holds) {
  714.     return (FALSE);
  715.   }
  716.  
  717. // Hit the representation with the testing matrix:
  718.  
  719.   Matrix rep = s.ToFull() * info->tstmtx;
  720.  
  721. // For affine subsets, the origin of the argument subset frame
  722. // must be in this subset, and the tangent space elements cannot
  723. // have an offset: 
  724.  
  725.   if (s.Holds() == AFFINE_SUBSET) {
  726.     Scalar testval = EPSILON;
  727.     toprow = rep.Rows() - 1;
  728.     if (info->s.Holds() == PROJ_SPACE) {
  729.       if (fabs(rep[s.info->isOffset][info->isOffset]
  730.       * s.info->offset) <= EPSILON) {
  731.         return (FALSE);
  732.       } else {  // Scale test value to reflect normalization to offset
  733.         Scalar factor = fabs(info->offset /
  734.                  rep[s.info->isOffset][info->isOffset]);
  735.         testval = testval / factor;
  736.       }
  737.     } else {
  738.       if (fabs((rep[s.info->isOffset][info->isOffset]
  739.       * s.info->offset) - info->offset) > EPSILON) {
  740.       return (FALSE);
  741.       }
  742.     }
  743.     for (int j = info->zerostart; j < rep.Columns(); j++) {
  744.       if (fabs(rep[s.info->isOffset][j]) > testval) {
  745.         return (FALSE);
  746.       }
  747.     }
  748.     for (int i = 0; i < toprow; i++) {
  749.       if (fabs(rep[i][info->isOffset]) > EPSILON) {
  750.         return (FALSE);
  751.       }
  752.     }
  753.   } else {
  754.     toprow = rep.Rows();
  755.   }
  756.  
  757. //  Each basis vector for the argument subset or subset tangent
  758. //  space must be contained in this subset or subset tangent space:
  759.  
  760.   for (int i = 0; i < toprow; i++) {
  761.     for (int j = info->zerostart; j < rep.Columns(); j++) {
  762.       if (fabs(rep[i][j]) > EPSILON) {
  763.         return (FALSE);
  764.       }
  765.     }
  766.   }
  767.   return (TRUE);
  768. }
  769.  
  770. // ***********************************************************************
  771. // ***********************************************************************
  772. //
  773. // VSubSet Class
  774. //
  775. // ***********************************************************************
  776. // ***********************************************************************
  777. //
  778. // Private/protected member functions
  779. //
  780. // ***********************************************************************
  781. //
  782. // Builds a standard subset for a vector space.  CAUTION:  Although this
  783. // is a single-argument constructor, it is NOT intended to be used to
  784. // cast a space into a subset!
  785.  
  786. VSubSet::VSubSet(VSpace& s)
  787. {
  788. // Create the new SubSetInfo:
  789.  
  790.   info = new SubSetInfo;
  791.   type = LINEAR_SUBSET;
  792.   holds = LINEAR_SUBSET;
  793.  
  794.   char* tag = this->BuildTagName("Standard subset for ", s);
  795.   this->CopyDebugName(tag);
  796.   this->DestroyTagName(tag);
  797.  
  798.   info->s = s;
  799.   info->t = holds;
  800.   info->d = s.Dim();
  801.   info->tstmtx = IdentityMatrix(info->d);
  802.   info->fullbas = IdentityMatrix(info->d);
  803.   info->isOffset = -1;
  804.   info->substart = 0;
  805.   info->zerostart = info->d;
  806.   info->offset = 0.0;
  807.   info->fromfull = IdentityMatrix(info->d);
  808.   info->tofull = IdentityMatrix(info->d);
  809.   info->accepts = s.NativeType();
  810. }
  811.  
  812. // ***********************************************************************
  813. //
  814. // Public member functions
  815. //
  816. // ***********************************************************************
  817. //
  818. // Memberwise assignment:
  819. //
  820.  
  821. VSubSet& VSubSet::operator=(VSubSet &s)
  822. {
  823.   info = s.info;
  824.   holds = s.holds;
  825.   return *this;
  826. }
  827.  
  828. // ***********************************************************************
  829. //
  830. // A subset can only be cast down to a vector subset if it is one (no
  831. // conversions).
  832. //
  833.  
  834. VSubSet::VSubSet(SubSet& s) : (s)
  835. {
  836.   type = LINEAR_SUBSET;
  837.   if ((holds != LINEAR_SUBSET) && (holds != NULL_SUBSET)) {
  838.       errh.ErrorExit("VSubSet::VSubSet(SubSet&)",
  839.                 "Attempted to cast a non-vector subset to a vector subset", s);
  840.   }
  841. }
  842.  
  843. // ***********************************************************************
  844. //
  845. // Output for debugging:
  846. //
  847.  
  848. void VSubSet::debug_out(ostream &c, int indent) 
  849. {
  850.   static char* name = "VSubSet object\n";
  851.   this->data_out(c, indent, name);
  852.   return;
  853. }
  854.  
  855. // ***********************************************************************
  856. //
  857. //  Build a vector subset of a vector space.
  858. //
  859.  
  860. VSubSet::VSubSet(char* namein, VSpace &s, GeObList &v)
  861. {
  862.   static char* sig = "VSubSet::VSubSet(char*, VSpace&, GeObList&)";
  863.   Boolean errflag;
  864.  
  865.   if (v.Length() < 1) {
  866.     errh.ErrorExit(sig, "Incorrect number of points specified", v);
  867.   }
  868.  
  869. // Create the SubSetInfo block:
  870.  
  871.   info = new SubSetInfo;
  872.   type = LINEAR_SUBSET;
  873.   holds = LINEAR_SUBSET;
  874.  
  875. // Important info:
  876.  
  877.   info->t = holds; 
  878.   info->d = v.Length();
  879.   info->s = s;
  880.   info->accepts = s.NativeType();
  881.   info->isOffset = -1;
  882.   info->substart = 0;
  883.   info->zerostart = info->d;
  884.   info->offset = 0.0;
  885.   this->CopyDebugName(namein);
  886.  
  887. // Make sure all the spanning objects are in the specified space:
  888.  
  889.   Matrix spantemp(v.Length(), s.Dim());
  890.   if (!(this->ConvertList(v, info->accepts, s, &spantemp))) {
  891.     errh.ErrorExit(sig,
  892.            "Object cannot be mapped into specified space", v, s);
  893.   }
  894.  
  895. // The user provides a list of geometric objects that span
  896. // some n-dimensional portion of the m-dimensional space.  They must
  897. // be independent.  We need to construct an orthonormal basis for
  898. // the embedding space such that the first n vectors span the 
  899. // subset, and the remaining vectors are orthogonal to the subset.
  900. // The orthonormal basis is built using Gram-Schmidt othogonalization.
  901. // Normalize the first vector:
  902.  
  903.   Scalar mag = sqrt((spantemp[0] * Transpose(spantemp[0]))[0][0]);
  904.   Matrix have = spantemp[0] / mag;
  905.  
  906. // Gram-Schmidt:
  907.  
  908.   info->tofull = this->GSO(have, spantemp, 1, info->d, &errflag);
  909.   if (errflag) {
  910.     errh.ErrorExit(sig, "Objects to define subset must be independent", v, s);
  911.   }
  912.   info->fullbas = this->GSO(info->tofull, IdentityMatrix(s.Dim()),
  913.                 0, s.Dim(), &errflag);
  914.   if (errflag) {
  915.     errh.ErrorExit(sig, "Unexpected error", v, s);
  916.   }
  917.  
  918. // Build the testing matrix and the projection matrix to convert 
  919. // "close" full space representations to subset representations:
  920.  
  921.   info->tstmtx = Inverse(info->fullbas);
  922.   Matrix trg = ZeroMatrix(s.Dim(), info->d);
  923.   for (int i = 0; i < info->d; i++) {
  924.     trg[i][i] = 1.0;
  925.   }
  926.   info->fromfull = info->tstmtx * trg; 
  927.  
  928. // ***********************************************************************
  929. // ***********************************************************************
  930. //
  931. // ASubSet Class
  932. //
  933. // ***********************************************************************
  934. // ***********************************************************************
  935. //
  936. // Private/protected member functions
  937. //
  938. // ***********************************************************************
  939. //
  940. // Builds a standard affine subset for a space.  CAUTION:  Although this
  941. // is a single-argument constructor, it is NOT intended to be used to
  942. // cast a space into a subset!
  943. //
  944.  
  945. ASubSet::ASubSet(Space& s)
  946. {
  947.   int size = s.MatrixSize();
  948.  
  949. // Create the new SubSetInfo:
  950.  
  951.   info = new SubSetInfo;
  952.   type = AFFINE_SUBSET;
  953.   holds = AFFINE_SUBSET;
  954.  
  955.   char* tag = this->BuildTagName("Standard affine subset for ", s);
  956.   this->CopyDebugName(tag);
  957.   this->DestroyTagName(tag);
  958.  
  959.   info->t = holds;
  960.   info->d = (s.Holds() == VEC_SPACE) ? s.Dim() - 1 : s.Dim();
  961.   info->s = s;
  962.   info->tstmtx = IdentityMatrix(size);
  963.   info->fullbas = IdentityMatrix(size);
  964.   info->isOffset = size - 1;
  965.   info->substart = 0;
  966.   info->zerostart = size;
  967.   info->offset = 1.0;
  968.   info->fromfull = IdentityMatrix(size);
  969.   info->tofull = IdentityMatrix(size);
  970.   info->accepts = s.NativeType();
  971. }
  972.  
  973. // ***********************************************************************
  974. //
  975. // Used to create a consistent standard affine subset, given a
  976. // projective map.
  977. //
  978.  
  979. ASubSet::ASubSet(ASubSet& a, ProjectiveMap& m)
  980. {
  981.   static char* sig = "ASubSet::ASubSet(ASubSet&, ProjectiveMap&)";
  982.   Boolean errflag;
  983.  
  984. // Create the new SubSetInfo block:
  985.  
  986.   info = new SubSetInfo;
  987.   type = AFFINE_SUBSET;
  988.   holds = AFFINE_SUBSET;
  989.  
  990.   info->t = holds;
  991.   info->s = m.Range().EmbeddingSpace();
  992.  
  993.   int dim = info->s.MatrixSize();
  994.  
  995.   info->d = (info->s.Holds() == VEC_SPACE) ? info->s.Dim() - 1 : info->s.Dim();
  996.   info->accepts = info->s.NativeType();
  997.   info->isOffset = dim - 1;
  998.   info->substart = 0;
  999.   info->zerostart = dim;
  1000.  
  1001.   char* tag = this->BuildTagName("Standard affine subset for ", info->s);
  1002.   this->CopyDebugName(tag);
  1003.   this->DestroyTagName(tag);
  1004.  
  1005. // The map had better be invertible.  Send the subset basis through
  1006. // the map, and recreate the subset:
  1007.  
  1008.   if (!m.Invertible()) {
  1009.     errh.ErrorExit(sig, "Requires invertible map", a, m);
  1010.   }
  1011.  
  1012.   if (a.EmbeddingSpace() != m.Domain().EmbeddingSpace()) {
  1013.     errh.ErrorExit(sig, "Domain mismatch", a, m);
  1014.   }
  1015.  
  1016. // This approach works, but is not elegant.
  1017. // Map the offset vector as a linear functional to keep it
  1018. // perpendicular to tangent space.  Map the subset basis
  1019. // as usual:
  1020.  
  1021.   Matrix pt = ((a.AugBasis())[a.IsOffset()] *
  1022.           Inverse(Transpose(m.MatrixRep())));
  1023.   Scalar mag = sqrt((pt * Transpose(pt))[0][0]);
  1024.   info->offset = a.Offset() / mag;
  1025.  
  1026.   Matrix span2 = a.AugBasis() * m.MatrixRep();
  1027.  
  1028. // Keep the offset vector intact by making it the first vector
  1029. // in the new basis:
  1030.  
  1031.   span2[a.IsOffset()] = span2[0];
  1032.   span2[0] = pt[0];
  1033.  
  1034. // Build a set of orthonormal vectors for the subspace, then
  1035. // augment with vectors orthogonal to the subspace:
  1036.  
  1037.   Matrix have = span2[0] / mag;
  1038.   info->tofull = this->GSO(have, span2, 1, dim, &errflag);
  1039.   if (errflag) {
  1040.     errh.ErrorExit(sig, "Unexpected error A", a, m);
  1041.   }
  1042.  
  1043. // Swap unchanged offset vector back into position:
  1044.  
  1045.   Matrix hold = info->tofull[0];
  1046.   info->tofull[0] = info->tofull[info->isOffset];
  1047.   info->tofull[info->isOffset] = hold[0];
  1048.  
  1049.   info->fullbas = this->GSO(info->tofull, IdentityMatrix(dim),
  1050.                 0, dim, &errflag);
  1051.   if (errflag) {
  1052.     errh.ErrorExit(sig, "Unexpected error B", a, m);
  1053.   }
  1054.  
  1055. // Calculate the testing matrix:
  1056.  
  1057.   info->tstmtx = Inverse(info->fullbas);
  1058.  
  1059. // Calculate fromfull:
  1060.  
  1061.   Matrix trg = ZeroMatrix(dim, dim);
  1062.   for (int i = 0; i < dim; i++) {
  1063.     trg[i][i] = 1.0;
  1064.   }
  1065.   info->fromfull = info->tstmtx * trg; 
  1066. }
  1067.  
  1068. // ***********************************************************************
  1069. //
  1070. // Public member functions
  1071. //
  1072. // ***********************************************************************
  1073. //
  1074. // A subset can only be cast down to an affine subset if it is one (no
  1075. // conversions).
  1076.  
  1077. ASubSet::ASubSet(SubSet& s) : (s)
  1078. {
  1079.   type = AFFINE_SUBSET;
  1080.   if ((holds != AFFINE_SUBSET) && (holds != NULL_SUBSET)) {
  1081.       errh.ErrorExit("ASubSet::ASubSet(SubSet&)",
  1082.                "Attempted to cast a non-affine subset to an affine subset", s);
  1083.   }
  1084. }
  1085.  
  1086. // ***********************************************************************
  1087. //
  1088. // Memberwise assignment:
  1089. //
  1090.  
  1091. ASubSet& ASubSet::operator=(ASubSet& s)
  1092. {
  1093.   info = s.info;
  1094.   holds = s.holds;
  1095.   return *this;
  1096. }  
  1097.  
  1098. // ***********************************************************************
  1099. //
  1100. // Output for debugging:
  1101. //
  1102.  
  1103. void ASubSet::debug_out(ostream &c, int indent) 
  1104. {
  1105.   static char* name = "ASubSet object\n";
  1106.   this->data_out(c, indent, name);
  1107.   return;
  1108. }
  1109.  
  1110. // ***********************************************************************
  1111. //
  1112. //  Build an affine subset of a vector or affine space.
  1113. //
  1114.  
  1115. ASubSet::ASubSet(char* namein, Space &s, GeObList &v)
  1116. {
  1117.   static char* sig = "ASubSet::ASubSet(char*, Space&, GeObList&)";
  1118.   Boolean errflag;
  1119.  
  1120.   if ((s.Holds() != VEC_SPACE) && (s.Holds() != AFF_SPACE)) {
  1121.     errh.ErrorExit(sig, "Vector or affine space required", s);
  1122.   }
  1123.  
  1124.   if (v.Length() < 1) {
  1125.     errh.ErrorExit(sig, "Incorrect number of points specified", v);
  1126.   }
  1127.  
  1128. // Create the new SubSetInfo block:
  1129.  
  1130.   info = new SubSetInfo;
  1131.   type = AFFINE_SUBSET;
  1132.   holds = AFFINE_SUBSET;
  1133.  
  1134. // Important info:
  1135.  
  1136.   info->t = holds; 
  1137.   info->d = v.Length() - 1;
  1138.   info->s = s;
  1139.   info->accepts = s.NativeType();
  1140.   info->isOffset = info->d;
  1141.   info->substart = 0;
  1142.   info->zerostart = info->d + 1;
  1143.   this->CopyDebugName(namein);
  1144.  
  1145. // Make sure all the spanning objects are in the specified space:
  1146.  
  1147.   int dim = s.MatrixSize();
  1148.   int num = v.Length();
  1149.  
  1150.   Matrix spantemp(num, dim);
  1151.   if (!(this->ConvertList(v, info->accepts, s, &spantemp))) {
  1152.     errh.ErrorExit(sig, "Object cannot be mapped into specified space", v, s);
  1153.   }
  1154.  
  1155. // The subset basis will be a frame for the affine subset, so we need
  1156. // to derive vectors in the tangent subset.  Keep the last point
  1157. // in the list as the point origin for the frame, and keep a separate
  1158. // copy of the point's matrix rep. to use for finding the offset.
  1159.  
  1160.   Matrix span2(num, dim);
  1161.   Matrix pt = spantemp[num - 1];
  1162.   int slot = 0;
  1163.   for (int i = 0; i < num; i++) {
  1164.     if (i == num - 1) {
  1165.       span2[i] = spantemp[i];
  1166.     } else {
  1167.  
  1168. // The following line of code produces a bug with g++ 1.37.1
  1169. // (no problem with CFRONT 1.2) when using dynamically allocated matrices:
  1170. //    span2[slot++] = (spantemp[i] - pt)[0];
  1171. // Replace it with:
  1172.  
  1173.       Matrix temp = (spantemp[i] - pt[0]);
  1174.       span2[slot++] = temp[0];
  1175.     }
  1176.   }
  1177.  
  1178. // Build a set of orthonormal vectors for the subspace, then
  1179. // augment with vectors orthogonal to the subspace:
  1180.  
  1181.   Scalar mag = sqrt((span2[0] * Transpose(span2[0]))[0][0]);
  1182.   Matrix have = span2[0] / mag;
  1183.   info->tofull = this->GSO(have, span2, 1, num, &errflag);
  1184.   if (errflag) {
  1185.     errh.ErrorExit(sig, "Objects to define subset must be independent", v, s);
  1186.   }
  1187.  
  1188.   info->fullbas = this->GSO(info->tofull, IdentityMatrix(dim),
  1189.                 0, dim, &errflag);
  1190.   if (errflag) {
  1191.     errh.ErrorExit(sig, "Unexpected error", v, s);
  1192.   }
  1193.  
  1194. // Testing matrix:
  1195.  
  1196.   info->tstmtx = Inverse(info->fullbas);
  1197.  
  1198. // Record the offset of the affine hyperplane (the projection of
  1199. // the original frame origin point onto the offset dimension):
  1200.  
  1201.   info->offset = (pt * Transpose(info->tofull[info->isOffset]))[0][0];
  1202.  
  1203. // Calculate fromfull:
  1204.  
  1205.   Matrix trg = ZeroMatrix(dim, num);
  1206.   for (int j = 0; j < num; j++) {
  1207.     trg[j][j] = 1.0;
  1208.   }
  1209.   info->fromfull = info->tstmtx * trg; 
  1210.  
  1211. // ***********************************************************************
  1212. //
  1213. // Build an affine subset of a projective space. The key here is 
  1214. // that the combination of the "regular" point and the
  1215. // "points at infinity" specify a projective subspace;
  1216. // subtracting the points at infinity turns this into an
  1217. // affine subset.
  1218. //
  1219.  
  1220. ASubSet::ASubSet(char* namein, PSpace& s, GeOb& v, GeObList& inf)
  1221. {
  1222.   static char* sig = "ASubSet::ASubSet(char*, PSpace&, GeOb&, GeObList&)";
  1223.   Boolean errflag;
  1224.  
  1225. // The number of points at infinity that are provided needs to be
  1226. // appropriate.  For an m-dimensional affine subset, we need m+1
  1227. // projective points, of which m are designated to be points at
  1228. // infinity, and only 1 is a "regular" point.
  1229.  
  1230.   if (inf.Length() < 1) {
  1231.     errh.ErrorExit(sig, "Incorrect number of points specified", inf);
  1232.   }
  1233.  
  1234. // Create a new SubSetInfo block:
  1235.  
  1236.   info = new SubSetInfo;
  1237.   type = AFFINE_SUBSET;
  1238.   holds = AFFINE_SUBSET;
  1239.  
  1240. // Important info:
  1241.  
  1242.   info->t = holds; 
  1243.   info->d = inf.Length();
  1244.   info->s = s;
  1245.   info->accepts = s.NativeType();
  1246.   info->isOffset = info->d;
  1247.   info->substart = 0;
  1248.   info->zerostart = info->d + 1;
  1249.   this->CopyDebugName(namein);
  1250.  
  1251. // Make sure all the spanning objects are in the specified space:
  1252.  
  1253.   int dim = s.MatrixSize();
  1254.  
  1255.   Matrix vtemp(1, dim);
  1256.   Matrix inftemp(inf.Length(), dim);
  1257.   GeObList vlst(v);
  1258.  
  1259.   if (!(this->ConvertList(vlst, info->accepts, s, &vtemp))) {
  1260.     errh.ErrorExit(sig, "Object cannot be mapped into specified space", v, s);
  1261.   }
  1262.   if (!(this->ConvertList(inf, info->accepts, s, &inftemp))) {
  1263.     errh.ErrorExit(sig,
  1264.            "Object cannot be mapped into specified space", inf, s);
  1265.   }
  1266.  
  1267. // Combine the matrix reps. of the two lists into a single matrix.
  1268.  
  1269.   int num = info->d + 1;
  1270.   Matrix span(num, dim);
  1271.   span[num - 1] = vtemp[0];
  1272.   for (int i = 0; i < num - 1; i++) {
  1273.     span[i] = inftemp[i];
  1274.   }
  1275.  
  1276. // Build a set of orthonormal vectors for the subset, then
  1277. // augment with vectors orthogonal to the subset:
  1278.  
  1279.   Scalar mag = sqrt((span[0] * Transpose(span[0]))[0][0]);
  1280.   Matrix have = span[0] / mag;
  1281.   info->tofull = this->GSO(have, span, 1, num, &errflag);
  1282.   if (errflag) {
  1283.     errh.ErrorExit(sig,
  1284.            "Objects to define subset must be independent", v, inf);
  1285.   }
  1286.   info->fullbas = this->GSO(info->tofull, IdentityMatrix(dim),
  1287.                 0, dim, &errflag);
  1288.   if (errflag) {
  1289.     errh.ErrorExit(sig, "Unexpected error", v, inf);
  1290.   }
  1291.  
  1292. // Build the testing matrix:
  1293.  
  1294.   info->tstmtx = Inverse(info->fullbas);
  1295.  
  1296. // Set the offset of the affine hyperplane at 1.0 (it can be any
  1297. // arbitrary non-zero value for affine subsets of projective spaces):
  1298.  
  1299.   info->offset = 1.0;
  1300.  
  1301. // Calculate fromfull:
  1302.  
  1303.   Matrix trg = ZeroMatrix(dim, num);
  1304.   for (int j = 0; j < num; j++) {
  1305.     trg[j][j] = 1.0;
  1306.   }
  1307.   info->fromfull = info->tstmtx * trg; 
  1308.  
  1309. // ***********************************************************************
  1310. // ***********************************************************************
  1311. //
  1312. // PSubSet Class
  1313. //
  1314. // ***********************************************************************
  1315. // ***********************************************************************
  1316. //
  1317. // Private/protected member functions
  1318. //
  1319. // ***********************************************************************
  1320. //
  1321. // Builds a standard projective subset for a space.
  1322. //
  1323.  
  1324. PSubSet::PSubSet(Space& s)
  1325. {
  1326.   static char* sig = "PSubSet::PSubSet(Space&)";
  1327.   int size = s.MatrixSize();
  1328.  
  1329.   if ((s.Holds() != VEC_SPACE) && (s.Holds() != PROJ_SPACE)) {
  1330.     errh.ErrorExit(sig, "Vector or projective space required", s);
  1331.   }
  1332.  
  1333. // Create a new SubSetInfo block:
  1334.  
  1335.   info = new SubSetInfo;
  1336.   type = PROJECTIVE_SUBSET;
  1337.   holds = PROJECTIVE_SUBSET;
  1338.  
  1339.   char* tag = this->BuildTagName("Standard proj. subset for ", s);
  1340.   this->CopyDebugName(tag);
  1341.   this->DestroyTagName(tag);
  1342.  
  1343.   info->t = holds;
  1344.   info->d = (s.Holds() == VEC_SPACE) ? s.Dim() - 1 : s.Dim();
  1345.   info->s = s;
  1346.   info->tstmtx = IdentityMatrix(size);
  1347.   info->fullbas = IdentityMatrix(size);
  1348.   info->isOffset = -1;
  1349.   info->substart = 0;
  1350.   info->zerostart = size;
  1351.   info->offset = 0.0;
  1352.   info->fromfull = IdentityMatrix(size);
  1353.   info->tofull = IdentityMatrix(size);
  1354.  
  1355.   info->accepts = s.NativeType();
  1356.   if (info->accepts == VECTOR) {
  1357.     info->accepts = VEC_EC;
  1358.   } else if (info->accepts == AFF_VECTOR) {
  1359.     info->accepts = AFF_VEC_EC;
  1360.   }
  1361. }
  1362.  
  1363. // ***********************************************************************
  1364. //
  1365. // Public member functions
  1366. //
  1367. // ***********************************************************************
  1368. //
  1369. // A subset can only be cast down to a proj. subset if it is one (no
  1370. // conversions).
  1371.  
  1372. PSubSet::PSubSet(SubSet& s) : (s)
  1373. {
  1374.   type = PROJECTIVE_SUBSET;
  1375.   if ((holds != PROJECTIVE_SUBSET) && (holds != NULL_SUBSET)) {
  1376.       errh.ErrorExit("PSubSet::PSubSet(SubSet&)",
  1377.        "Attempted to cast a non-projective subset to a projective subset", s);
  1378.   }
  1379. }
  1380.  
  1381. // ***********************************************************************
  1382. //
  1383. // Memberwise assignment:
  1384. //
  1385.  
  1386. PSubSet& PSubSet::operator=(PSubSet &s)
  1387. {
  1388.   info = s.info;
  1389.   holds = s.holds;
  1390.   return *this;
  1391. }  
  1392.  
  1393. // ***********************************************************************
  1394.  
  1395. void PSubSet::debug_out(ostream &c, int indent) 
  1396. {
  1397.   static char* name = "PSubSet object\n";
  1398.   this->data_out(c, indent, name);
  1399.   return;
  1400. }
  1401.  
  1402. // ***********************************************************************
  1403. //
  1404. //  Build a projective subspace, without base point specification.
  1405. //
  1406.  
  1407. PSubSet::PSubSet(char* namein, Space &s, GeObList &v)
  1408. {
  1409.   static char* sig = "PSubSet::PSubSet(char*, Space&, GeObList&)";
  1410.   Boolean errflag;
  1411.  
  1412.   if ((s.Holds() != VEC_SPACE) && (s.Holds() != PROJ_SPACE)) {
  1413.     errh.ErrorExit(sig, "Vector or Projective space required", s);
  1414.   }
  1415.  
  1416.   if (v.Length() < 1) {
  1417.     errh.ErrorExit(sig, "Incorrect number of points specified", v);
  1418.   }
  1419.  
  1420. // Create a new SubSetInfo block:
  1421.  
  1422.   info = new SubSetInfo;
  1423.   type = PROJECTIVE_SUBSET;
  1424.   holds = PROJECTIVE_SUBSET;
  1425.  
  1426. // Important info:
  1427.  
  1428.   info->t = holds; 
  1429.   info->d = v.Length() - 1;
  1430.   info->s = s;
  1431.   info->isOffset = -1;
  1432.   info->substart = 0;
  1433.   info->zerostart = info->d + 1;
  1434.   info->offset = 0.0;
  1435.   this->CopyDebugName(namein);
  1436.  
  1437.   info->accepts = s.NativeType();
  1438.   if (info->accepts == VECTOR) {
  1439.     info->accepts = VEC_EC;
  1440.   } else if (info->accepts == AFF_VECTOR) {
  1441.     info->accepts = AFF_VEC_EC;
  1442.   }
  1443.  
  1444. // Make sure all the spanning objects are in the specified space:
  1445.  
  1446.   int dim = s.MatrixSize();
  1447.   int num = v.Length();
  1448.  
  1449.   Matrix spantemp(num, dim);
  1450.   if (!(this->ConvertList(v, info->accepts, s, &spantemp))) {
  1451.     errh.ErrorExit(sig,
  1452.            "Object cannot be mapped into specified space", v, s);
  1453.   }
  1454.  
  1455. // Build a set of orthonormal vectors for the subspace, then
  1456. // augment with vectors orthogonal to the subspace:
  1457.  
  1458.   Scalar mag = sqrt((spantemp[0] * Transpose(spantemp[0]))[0][0]);
  1459.   Matrix have = spantemp[0] / mag;
  1460.   info->tofull = this->GSO(have, spantemp, 1, num, &errflag);
  1461.   if (errflag) {
  1462.     errh.ErrorExit(sig, "Objects to define subset must be independent", v, s);
  1463.   }
  1464.   info->fullbas = this->GSO(info->tofull, IdentityMatrix(dim),
  1465.                 0, dim, &errflag);
  1466.   if (errflag) {
  1467.     errh.ErrorExit(sig, "Unexpected error", v, s);
  1468.   }
  1469.  
  1470. // Build testing matrix and fromfull matrix:
  1471.  
  1472.   info->tstmtx = Inverse(info->fullbas);
  1473.   Matrix trg = ZeroMatrix(dim, num);
  1474.   for (int i = 0; i < num; i++) {
  1475.     trg[i][i] = 1.0;
  1476.   }
  1477.   info->fromfull = info->tstmtx * trg; 
  1478.  
  1479. // ***********************************************************************
  1480. //
  1481. // Build a projective subset of a projective space by selection of
  1482. // base points.  In combination, base points and other points
  1483. // define a projective subset.  The subsequent removal of the
  1484. // base points reduces the dimensionality of the subset.  The
  1485. // resulting dimensionality equals that of the corresponding
  1486. // primitive geometric form (e.g. pencil or bundle).
  1487. //
  1488.  
  1489. PSubSet::PSubSet(char* namein, Space& s, GeObList& bp, GeObList& v)
  1490. {
  1491.   static char* sig = "PSubSet::PSubSet(char*, Space&, GeObList&, GeObList&)";
  1492.   Boolean errflag;
  1493.   int num = v.Length() + bp.Length();
  1494.  
  1495.   if ((s.Holds() != VEC_SPACE) && (s.Holds() != PROJ_SPACE)) {
  1496.     errh.ErrorExit(sig, "Vector or Projective space required", s);
  1497.   }
  1498.  
  1499.   if ((v.Length() < 1) || (bp.Length() < 1)) {
  1500.     errh.ErrorExit(sig, "Incorrect number of points specified", bp, v);
  1501.   }
  1502.  
  1503. // Create a new SubSetInfo block:
  1504.  
  1505.   info = new SubSetInfo;
  1506.   type = PROJECTIVE_SUBSET;
  1507.   holds = PROJECTIVE_SUBSET;
  1508.  
  1509. // Important info:
  1510.  
  1511.   info->t = holds; 
  1512.   info->d = v.Length() - 1;
  1513.   info->s = s;
  1514.   info->isOffset = -1;
  1515.   info->substart = bp.Length();
  1516.   info->zerostart = num;
  1517.   info->offset = 0.0;
  1518.   this->CopyDebugName(namein);
  1519.  
  1520.   info->accepts = s.NativeType();
  1521.   if (info->accepts == VECTOR) {
  1522.     info->accepts = VEC_EC;
  1523.   } else if (info->accepts == AFF_VECTOR) {
  1524.     info->accepts = AFF_VEC_EC;
  1525.   }
  1526.  
  1527. // Make sure all the spanning objects are in the specified space:
  1528.  
  1529.   int dim = s.MatrixSize();
  1530.  
  1531.   Matrix spantemp(v.Length(), dim);
  1532.   Matrix bptemp(bp.Length(), dim);
  1533.  
  1534.   if (!(this->ConvertList(v, info->accepts, s, &spantemp))) {
  1535.     errh.ErrorExit(sig,
  1536.            "Object cannot be mapped into specified space", v, s);
  1537.   }
  1538.   if (!(this->ConvertList(bp, info->accepts, s, &bptemp))) {
  1539.     errh.ErrorExit(sig,
  1540.            "Object cannot be mapped into specified space", bp, s);
  1541.   }
  1542.  
  1543. // Build a set of orthonormal vectors that span the space of base points.
  1544. // Then build an orthogonal basis to represent the subset, and finally
  1545. // add enough vectors to fill the basis out.  Note that we 
  1546. // CANNOT build a matrix that converts basis std. coords. to full space
  1547. // std. coords (tofull), since fromfull is not invertible.
  1548.  
  1549.   Scalar mag = sqrt((bptemp[0] * Transpose(bptemp[0]))[0][0]);
  1550.   Matrix have = bptemp[0] / mag;
  1551.   Matrix temp = this->GSO(have, bptemp, 1, bp.Length(), &errflag);
  1552.   if (errflag) {
  1553.     errh.ErrorExit(sig,
  1554.            "Objects to define subset must be independent", s, bp, v);
  1555.   }
  1556.   temp = this->GSO(temp, spantemp, 0, num, &errflag);
  1557.   if (errflag) {
  1558.     errh.ErrorExit(sig,
  1559.            "Objects to define subset must be independent", s, bp, v);
  1560.   }
  1561.   info->fullbas = this->GSO(temp, IdentityMatrix(dim), 0, dim, &errflag);
  1562.   if (errflag) {
  1563.     errh.ErrorExit(sig, "Unexpected error", s, bp, v);
  1564.   }
  1565.  
  1566. // Build testing matrix and fromfull matrix:
  1567.  
  1568.   info->tstmtx = Inverse(info->fullbas);
  1569.  
  1570.   Matrix trg = ZeroMatrix(dim, v.Length());
  1571.   int slot = 0;
  1572.   for (int i = bp.Length(); i < num; i++) {
  1573.     trg[i][slot++] = 1.0;
  1574.   }
  1575.   info->fromfull = info->tstmtx * trg; 
  1576.  
  1577.  
  1578. // ***********************************************************************
  1579. // ***********************************************************************
  1580. //
  1581. // Create the error information block:
  1582. //
  1583.  
  1584. static SubSetInfo errInfo("Uninitialized subset", 0);
  1585.  
  1586. // ***********************************************************************
  1587.